
// -----------------------------------------------------------------------------

#pragma once

#include "Win32.String.h"
#include "Win32.StringLinkList.h"
#include "Win32.DateTime.h"
#include "Win32.Number.h"

namespace Kif
{
namespace Win32
{
namespace Xml
{

enum XmlEncoding
{
   XmlEncodingUtf8 = 8,
   XmlEncodingUtf16 = 16,
   XmlEncodingIso88591 = 88591,
   XmlEncodingWindows1252 = 1252
}  ;

struct XmlEncodingLiteral
{
public:

   /// <summary>Get the Literal for given encoding</summary>
   /// <param name="encoding">encoding enumerator</param>
   /// <param name="encodingText">encoding String where to store Literal</param>
   /// <returns>the literal is returned if encoding is not supported the
   /// default (UTF-8) encoding literal is returned</returns>
   static Kif::Win32::String *GetLiteral(
      XmlEncoding encoding, Kif::Win32::String *encodingText)
   {

      static TCHAR LiteralUtf8[] = L"<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
      static TCHAR LiteralUtf16[] =
         L"<?xml version=\"1.0\" encoding=\"UTF-16\"?>";
      static TCHAR LiteralIso88591[] =
         L"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>";
      static TCHAR LiteralWindows1252[] =
         L"<?xml version=\"1.0\" encoding=\"windows-1252\"?>";

      if (encodingText == NULL)
         encodingText = new Kif::Win32::String();
      switch (encoding)
      {
         case XmlEncodingUtf16:
            encodingText->Copy(LiteralUtf8, SizeOf(LiteralUtf8));
            break;
         case XmlEncodingIso88591:
            encodingText->Copy(LiteralIso88591, SizeOf(LiteralIso88591));
            break;
         case XmlEncodingWindows1252:
            encodingText->Copy(LiteralWindows1252, SizeOf(LiteralWindows1252));
            break;
         default:
            encodingText->Copy(LiteralUtf8, SizeOf(LiteralUtf8));
      }
      return encodingText;
   }

   static Kif::Win32::String *GetLiteral(XmlEncoding encoding)
   {
      return GetLiteral(encoding, NULL);
   }

   static Kif::Win32::String *GetLiteral(
      XmlEncoding encoding,Kif::Win32::String &encodingText)
   {
      return GetLiteral(encoding, &encodingText);
   }

}  ;  // end of XmlEncodingLiteral

class XmlWriter
{
public:

   inline static Kif::Win32::String *WriteAttribute(
      TCHAR *attributeName, size_t attributeNameLength,
      TCHAR *value, size_t valueLength,
      Kif::Win32::String *outString)
   {
      TCHAR eq[] = _T("=\"");
      TCHAR ed[] = _T("\"");
      outString->Concat(attributeName,attributeNameLength);
      outString->Concat(eq,SizeOf(eq));
      outString->Concat(value,valueLength);
      outString->Concat(ed,SizeOf(ed));
      return(outString);
   }

   inline static Kif::Win32::String *WriteAttribute(
      TCHAR *attributeName, size_t attributeNameLength,
      TCHAR *value, size_t valueLength,
      Kif::Win32::String &outString)
   {
      return(WriteAttribute(attributeName, attributeNameLength,
         value, valueLength, &outString));
   }

   inline static Kif::Win32::String *WriteStartTag(
      TCHAR *tag, size_t tagLength, Kif::Win32::String *outString)
   {
      TCHAR sTag[] = _T("<");
      TCHAR eTag[] = _T(">");
      outString->Concat(sTag,SizeOf(sTag));
      outString->Concat(tag,tagLength);
      outString->Concat(eTag,SizeOf(eTag));
      return(outString);
   }  // end of WriteStartTag

   /// <summary>Write Start Tag and given text line Attributes that is
   /// is assumed to be well formed.</summary>
   inline static Kif::Win32::String *WriteStartTag(
      TCHAR *tag, size_t tagLength,
      TCHAR *tagAttributes, size_t tagAttributesLength,
      Kif::Win32::String *outString)
   {
      TCHAR sTag[] = _T("<");
      TCHAR eTag[] = _T(">");
      TCHAR bTag[] = _T(" ");
      outString->Concat(sTag,SizeOf(sTag));
      outString->Concat(tag,tagLength);
      outString->Concat(bTag,SizeOf(bTag));
      outString->Concat(tagAttributes,tagAttributesLength);
      outString->Concat(eTag,SizeOf(eTag));
      return(outString);
   }  // end of WriteStartTag

   inline static Kif::Win32::String *WriteStartTag(
      TCHAR *tag, size_t tagLength, Kif::Win32::String &outString)
   {
      return(WriteStartTag(tag,tagLength,&outString));
   }

   inline static Kif::Win32::String *WriteEndTag(
      TCHAR *tag, size_t tagLength, Kif::Win32::String *outString)
   {
      TCHAR sTag[] = _T("</");
      TCHAR eTag[] = _T(">");
      outString->Concat(sTag,SizeOf(sTag));
      outString->Concat(tag,tagLength);
      outString->Concat(eTag,SizeOf(eTag));
      return(outString);
   }  // end of WriteEndTag

   inline static Kif::Win32::String *WriteEndTag(
      TCHAR *tag, size_t tagLength, Kif::Win32::String &outString)
   {
      return(WriteEndTag(tag,tagLength,&outString));
   }

   inline static Kif::Win32::String *WriteElement(
      TCHAR *tag,  size_t tagLength,
      TCHAR *data, size_t dataLength,
      Kif::Win32::String *outString)
   {
      if ((data == NULL) || (tag == NULL))
         return(outString);

      // write element
      WriteStartTag(tag,tagLength,outString);
      outString->Concat(data,dataLength);
      WriteEndTag(tag,tagLength,outString);
      return(outString);
   }  // end of WriteElement

   inline static Kif::Win32::String *WriteElement(
      TCHAR *tag,  size_t tagLength,
      long value,
      Kif::Win32::String *outString)
   {
      if (tag == NULL)
         return(outString);

      // write element
      WriteStartTag(tag,tagLength,outString);
      Kif::Win32::String v;
      Kif::Win32::Number::ToString(v,value);
      outString->Concat(v);
      WriteEndTag(tag,tagLength,outString);

      return(outString);
   }  // end of WriteElement

   inline static Kif::Win32::String *WriteElement(
      TCHAR *tag,  size_t tagLength,
      Kif::Win32::String *data,
      Kif::Win32::String *outString)
   {
      if (data == NULL)
         return(outString);
      return(WriteElement(
         tag,tagLength,data->GetBuffer(),data->GetLength(),outString));
   }  // end of WriteElement

   inline static Kif::Win32::String *WriteDate(Kif::Win32::String *outString)
   {
      TCHAR dateTag[]       = _T("<date>");
      TCHAR dateEndTag[]    = _T("</date>");

      // write date
      outString->Concat(dateTag,SizeOf(dateTag));
      Kif::Win32::String *s = Kif::Win32::DateTime::GetYmdHmsString();
      outString->Concat(s);
      delete s;
      outString->Concat(dateEndTag,SizeOf(dateEndTag));
      return(outString);
   }  // end of WriteDate

   inline static Kif::Win32::String *WriteElement(
      TCHAR *tag, DWORD tagLength,
      Kif::Win32::String *attributes, int attributeCount,
      Kif::Win32::String *outString)
   {
      TCHAR sTag[] = _T("<");
      TCHAR pTag[] = _T(" ");
      TCHAR eTag[] = _T(">");

      outString->Concat(sTag,SizeOf(sTag));
      outString->Concat(tag,tagLength);

      // append given attributes if any
      if (attributes)
      {
         int i;
         for (i=0; i < attributeCount; i++)
         {
            outString->Concat(pTag,SizeOf(pTag));
            outString->Concat(attributes[i]);
         }
      }

      outString->Concat(eTag,SizeOf(eTag));
      return(outString);
   }  // end of XmlDocument (ctor)

   inline static Kif::Win32::String *WriteElement(
      TCHAR *tag, DWORD tagLength,
      Kif::Win32::String *attributes, int attributeCount,
      Kif::Win32::String &outString)
   {
      return(WriteElement(tag,tagLength,attributes,attributeCount,&outString));
   }

}  ; // end of XmlWriter class

// -----------------------------------------------------------------------------

namespace XmlDocumentElements
{
   extern TCHAR xmlVersion[];
}  // end of XmlDocumentElements

namespace XmlDocumentTags
{
   //extern TCHAR xmlVersion[];
}  // end of XmlDocumentTags

class XmlDocument
{
private:
   Kif::Win32::StringLinkList linkList;

   void InitDocument(TCHAR *tag, DWORD tagLength,
      Kif::Win32::String *attributes, int attributeCount);

public:
   Kif::Win32::String XmlText;

   XmlDocument(XmlEncoding encoding)
   {
      Kif::Win32::String e;
      XmlEncodingLiteral::GetLiteral(encoding, e);
      XmlText.Copy(e);
   }

   XmlDocument()
   {
      Kif::Win32::String e;
      XmlEncodingLiteral::GetLiteral(XmlEncodingWindows1252, e);
      XmlText.Copy(e);
   }

   XmlDocument(TCHAR *tag, DWORD tagLength,
      Kif::Win32::String *attributes, int attributeCount)
   {
      InitDocument(tag, tagLength, attributes, attributeCount);
   }

   XmlDocument(TCHAR *tag, DWORD tagLength)
   {
      InitDocument(tag, tagLength, NULL, 0);
   }

   inline void AppendString(TCHAR *string, DWORD stringLength)
   {
      XmlText.Concat(string,stringLength);
   }

   inline void AppendString(Kif::Win32::String *string)
   {
      if (string == NULL)
         return;
      XmlText.Concat(string);
   }

   inline void AppendString(Kif::Win32::String &string)
   {
      XmlText.Concat(&string);
   }

   void WriteStartTag(TCHAR *tag, size_t tagLength,
      TCHAR *tagAttributes, size_t tagAttributesLength);

   void WriteStartTag(TCHAR *tag, size_t tagLength,
      Kif::Win32::String *attributes)
   {
      WriteStartTag(tag, tagLength, attributes->GetBuffer(),
         attributes->GetLength());
   }

   void WriteStartTag(TCHAR *tag, size_t tagLength,
      Kif::Win32::String &attributes)
   {
      WriteStartTag(tag, tagLength, attributes.GetBuffer(),
         attributes.GetLength());
   }

   void WriteStartTag(TCHAR *tag, size_t tagLength);
   void WriteStartTag(Kif::Win32::String *tag)
   {
      if (tag == NULL)
         return;
      WriteStartTag(tag->GetBuffer(), tag->GetLength());
   }
   void WriteStartTag(Kif::Win32::String &tag)
   {
      WriteStartTag(tag.GetBuffer(), tag.GetLength());
   }

   void WriteEndTag();

   inline Kif::Win32::String *ToXmlString()
   {
      return(&XmlText);
   }

   bool ToFile(TCHAR *outFilePath);

}  ;  // end of XmlDocument

}  // end of Kif::Win32::Xml namespace
}  // end of Kif::Win32 namespace
}  // end of Kif namespace
